home *** CD-ROM | disk | FTP | other *** search
/ ETO Development Tools 2 / ETO Development Tools 2.iso / Tools - Objects / MacApp / MacApp CD Release / MacApp 2.0.1 (Many Libraries) / Libraries / UMenuSetup.inc1.p < prev    next >
Encoding:
Text File  |  1990-10-25  |  20.6 KB  |  809 lines  |  [TEXT/MPS ]

  1. {$P}
  2. {[a-,body+,h-,o=100,r+,rec+,t=4,u+,#+,j=20/57/1$,n-]}
  3. { UMenuSetup.inc1.p }
  4. { Copyright © 1984-1990 by Apple Computer Inc. All rights reserved. }
  5.  
  6. {--------------------------------------------------------------------------------------------------}
  7.  
  8. CONST
  9.     _MAInvalMenuBar = $A81D;            { Trap number for invalidate menu bar on 7.0 systems }
  10.  
  11. TYPE
  12.     { the following must match the declaration in the PostRez tool }
  13.     MenuCmdRecord        = RECORD
  14.         theCmdNumber:        INTEGER;
  15.         theMenuNumber:        INTEGER;
  16.         theItemNumber:        INTEGER;
  17.         END;
  18.  
  19.     CmdTable            = ARRAY [1..4000] OF MenuCmdRecord; { Actually variable length }
  20.     CmdTablePtr         = ^CmdTable;
  21.     CmdTableHandle        = ^CmdTablePtr;
  22.  
  23.     MAMenuCRsrcPtr        = ^MAMenuCRsrc;                    {!!! After MPW 3.1 use the PInterfaces vers }
  24.     MAMenuCRsrcHandle    = ^MAMenuCRsrcPtr;
  25.     MAMenuCRsrc         = RECORD
  26.         numEntries:         INTEGER;                    {number of entries}
  27.         data:                ARRAY [1..1] OF MCEntry;
  28.         END;
  29.  
  30. PROCEDURE MAInvalMenuBar;
  31. INLINE _MAInvalMenuBar;
  32. { The trap name will be InvalMenuBar. The trap number will be $A81D. It will
  33. test as unimplemented on old systems. (There will also be a Gestalt selector.) }
  34.  
  35. {--------------------------------------------------------------------------------------------------}
  36.  
  37. VAR
  38.     pHNullMenuProc:     Handle;                         { Handle to null menu proc }
  39.  
  40.     pCmdTable:            CmdTableHandle;                 { maps CmdNumber <--> (menu,item) }
  41.     pSizeCmdTable:        INTEGER;                        { number of records in pCmdTable }
  42.  
  43. {--------------------------------------------------------------------------------------------------}
  44.  
  45. PROCEDURE NullMenuProc(message: INTEGER;
  46.                        aMenuHandle: MenuHandle;
  47.                        VAR menuRect: Rect;
  48.                        hitPt: Point;
  49.                        VAR whichItem: INTEGER);
  50.     FORWARD;
  51.  
  52. {--------------------------------------------------------------------------------------------------}
  53. {$IFC qDebug}
  54. {$S MADebug}
  55.  
  56. FUNCTION TraceMenuName(aCmd: CmdNumber): CHAR;
  57. { For debugging purposes only--used to dump the name and number of a command }
  58.  
  59.     VAR
  60.         cmdName:            Str255;
  61.  
  62.     BEGIN
  63.     CmdToName(aCmd, cmdName);
  64.     Write(aCmd: 1, ' [', cmdName, '],');
  65.     TraceMenuName := ' ';
  66.     END;
  67. {$ENDC}
  68.  
  69. {--------------------------------------------------------------------------------------------------}
  70. {$S MAMenuRes}
  71.  
  72. PROCEDURE InvalidateMenus;
  73.  
  74.     BEGIN
  75.     gMenusAreSetup := FALSE;
  76.     END;
  77.  
  78. {--------------------------------------------------------------------------------------------------}
  79. {$S MAMenuRes}
  80.  
  81. PROCEDURE ValidateMenus;
  82.  
  83.     BEGIN
  84.     gMenusAreSetup := TRUE;
  85.     END;
  86.  
  87. {--------------------------------------------------------------------------------------------------}
  88. {$S MAMenuRes}
  89.  
  90. FUNCTION MenusHavePendingUpdate: Boolean;
  91.  
  92.     BEGIN
  93.     MenusHavePendingUpdate := NOT gMenusAreSetup;
  94.     END;
  95.  
  96. {--------------------------------------------------------------------------------------------------}
  97. {$S MAMenuRes}
  98.  
  99. PROCEDURE InvalidateMenuBar;
  100.  
  101.     BEGIN
  102.     InvalidateMenus;                                    { if the menubar is invalidated then the
  103.                                                          menu items must be also }
  104.  
  105.  
  106.     { On systems that have invalidate menu bar use that functionality instead of setting the global.
  107.     The system will redraw the menu bar at the next convenient time. }
  108.     IF (gConfiguration.systemVersion >= $0600) & TrapExists(_MAInvalMenuBar) THEN
  109.         BEGIN
  110.         MAInvalMenuBar;
  111.         gRedrawMenuBar := FALSE;
  112.         END
  113.     ELSE
  114.         gRedrawMenuBar := TRUE;
  115.     END;
  116.  
  117. {--------------------------------------------------------------------------------------------------}
  118. {$S MAMenuRes}
  119.  
  120. PROCEDURE ValidateMenuBar;
  121.  
  122.     BEGIN
  123.     gRedrawMenuBar := FALSE;
  124.     END;
  125.  
  126. {--------------------------------------------------------------------------------------------------}
  127. {$S MAMenuRes}
  128.  
  129. FUNCTION MenuBarHasPendingUpdate;
  130.  
  131.     BEGIN
  132.     MenuBarHasPendingUpdate := gRedrawMenuBar;
  133.     END;
  134.  
  135. {--------------------------------------------------------------------------------------------------}
  136. {$S MAMenuRes}
  137.  
  138. FUNCTION CmdEnabled(cmd: CmdNumber): Boolean;
  139.  
  140.     VAR
  141.         menuNo, itemNo:     INTEGER;
  142.         theMenu:            MenuHandle;
  143.  
  144.     BEGIN
  145.     theMenu := CmdToComponents(cmd, menuNo, itemNo);
  146.  
  147.     IF theMenu <> NIL THEN
  148.         IF (itemNo > 0) & (itemNo < 32) THEN
  149.             CmdEnabled := BTst(theMenu^^.enableFlags, itemNo)
  150.         ELSE
  151.             CmdEnabled := TRUE
  152.     ELSE
  153.         CmdEnabled := FALSE;
  154.     END;
  155.  
  156. {--------------------------------------------------------------------------------------------------}
  157. {$S MAMenuRes}
  158.  
  159. FUNCTION CmdFromMenuItem(menu, item: INTEGER): CmdNumber;
  160.  { Given a menuID/item # return the appropriate command number. IF there
  161.   is no such command number, return -BOR(BSL(menu, 8), item).  If the
  162.   item number is <0 then assume that it is a negative command number. }
  163.  
  164.     VAR
  165.         i:                    INTEGER;
  166.         p:                    CmdTablePtr;
  167.  
  168.     BEGIN
  169.     IF item < 0 THEN
  170.         CmdFromMenuItem := - item
  171.     ELSE
  172.         BEGIN
  173.         IF item > 0 THEN
  174.             BEGIN
  175.             p := pCmdTable^;
  176.  
  177.             FOR i := 1 TO pSizeCmdTable DO
  178.                 WITH p^[i] DO
  179.                     IF (menu = theMenuNumber) & (item = theItemNumber) THEN
  180.                         BEGIN
  181.                         CmdFromMenuItem := theCmdNumber;
  182.                         Exit(CmdFromMenuItem);
  183.                         END;
  184.             END;
  185.         {$IFC qDebug}
  186.         IF (menu > 127) | (item > 255) THEN
  187.             BEGIN
  188.             Writeln('menu = ', menu: 1, '  item = ', item: 1);
  189.             Writeln('Menu/item number is too big for a negative command number!');
  190.             ProgramBreak('Try using a negative item number instead.');
  191.             END;
  192.         {$ENDC}
  193.  
  194.         CmdFromMenuItem := - BOR(BSL(menu, 8), item);
  195.         END;
  196.     END;
  197.  
  198. {--------------------------------------------------------------------------------------------------}
  199. {$S MAMenuRes}
  200.  
  201. PROCEDURE CmdToMenuItem(aCmd: CmdNumber;
  202.                         VAR menu, item: INTEGER);
  203.  
  204.     VAR
  205.         p:                    CmdTablePtr;
  206.         low:                INTEGER;
  207.         high:                INTEGER;
  208.         test:                INTEGER;
  209.  
  210.     BEGIN
  211.     IF aCmd < 0 THEN
  212.         BEGIN
  213.         menu := BSR( - aCmd, 8);
  214.         item := BAND( - aCmd, 255);
  215.         END
  216.     ELSE
  217.         BEGIN
  218.         { Use a binary search to find the command number in the table }
  219.         low := 1;
  220.         high := pSizeCmdTable;
  221.  
  222.         p := pCmdTable^;
  223.         WHILE low <= high DO
  224.             BEGIN
  225.             test := BSR(low + high, 1);                 { (low + high) DIV 2 }
  226.             WITH p^[test] DO
  227.                 IF aCmd = theCmdNumber THEN
  228.                     BEGIN
  229.                     menu := theMenuNumber;
  230.                     item := theItemNumber;
  231.                     Exit(CmdToMenuItem);
  232.                     END
  233.                 ELSE IF aCmd < theCmdNumber THEN
  234.                     high := test - 1
  235.                 ELSE
  236.                     low := test + 1;
  237.             END;
  238.  
  239.         { not found }
  240.         menu := 0;
  241.         item := 0;
  242.         END;
  243.     END;
  244.  
  245. {--------------------------------------------------------------------------------------------------}
  246. {$S MAMenuRes}
  247.  
  248. PROCEDURE CmdToName(aCmd: CmdNumber;
  249.                     VAR menuText: Str255);
  250.  
  251.     VAR
  252.         aMenu:                INTEGER;
  253.         anItem:             INTEGER;
  254.         mHandle:            MenuHandle;
  255.  
  256.     BEGIN
  257.     menuText := '';
  258.  
  259.     mHandle := CmdToComponents(aCmd, aMenu, anItem);
  260.     IF mHandle <> NIL THEN
  261.         GetItem(mHandle, anItem, menuText);
  262.     END;
  263.  
  264. {--------------------------------------------------------------------------------------------------}
  265. {$S MAMenuRes}
  266.  
  267. FUNCTION CmdToComponents(cmd: CmdNumber; VAR menuNo, itemNo: integer): MenuHandle;
  268.  
  269.     VAR
  270.         theMenu: MenuHandle;
  271.  
  272.     BEGIN
  273.     CmdToMenuItem(cmd, menuNo, itemNo);
  274.     IF menuNo <> 0 THEN { was found }
  275.         CmdToComponents := MAGetMenu(menuNo)
  276.     ELSE
  277.         CmdToComponents := NIL;
  278.     END;
  279.  
  280. {--------------------------------------------------------------------------------------------------}
  281. {$S MAMenuRes}
  282.  
  283. PROCEDURE EachMenuDo(PROCEDURE DoToMenu(aMenuHandle: MenuHandle; isHierarchical: Boolean);
  284.                      includeHierarchical: Boolean);
  285.  { Calls DoToMenu for each menu in the menu bar, including the
  286.   hierarchical and popup menus if includeHierarchical is TRUE. }
  287.     CONST
  288.         kHierArchical        = TRUE;
  289.         kNotHierArchical    = NOT kHierArchical;
  290.  
  291.     TYPE
  292.         { See IM V, Menu Manager, 'Menu Mgr Data Structures' pp.228-30 }
  293.         MAMenuRec            = RECORD
  294.             menuOH:             MenuHandle;             { menu's data }
  295.             menuLeft:            INTEGER;                { pixels }
  296.             END;
  297.         MAMenuRecPtr        = ^MAMenuRec;
  298.  
  299.         MAHMenuRec            = RECORD
  300.             menuOH:             MenuHandle;             { hierarchical menu's data }
  301.             reserved:            INTEGER;                { reserved for future use }
  302.             END;
  303.         MAHMenuRecPtr        = ^MAHMenuRec;
  304.  
  305.         MADynamicMenuList    = RECORD
  306.             lastMenu:            INTEGER;                { Offset }
  307.             lastRight:            INTEGER;                { Pixels }
  308.             mbResID:            INTEGER;
  309.             menu:                ARRAY [0..0] OF MAMenuRec; { Variable number of menus }
  310.  
  311.             lastHMenu:            INTEGER;                { Offset }
  312.             menuTitleSave:        PixMapHandle;            { handle to bits behind inverted menu title
  313.                                                          }
  314.             hMenu:                 ARRAY [0..0] OF MAHMenuRec; { Variable number of menus }
  315.             END;
  316.         MADynamicMenuListPtr = ^MADynamicMenuList;
  317.         MADynamicMenuListHandle = ^MADynamicMenuListPtr;
  318.     
  319.     VAR
  320.         wasLocked:            BOOLEAN;
  321.  
  322.     PROCEDURE WalkAMenuRecArray(aMenuRecPtr: MAMenuRecPtr;
  323.                                 lastMenuOffset: INTEGER;
  324.                                 isHierarchical: Boolean);
  325.     { NOTE: Assumes a MAMenuRec and a MAHMenuRec are the same size }
  326.  
  327.         VAR
  328.             aMenuHandle:        MenuHandle;
  329.             endAddress:            MAMenuRecPtr;
  330.  
  331.         BEGIN
  332.         endAddress := MAMenuRecPtr(ORD(aMenuRecPtr) + lastMenuOffset);
  333.         While (ORD(aMenuRecPtr) < ORD(endAddress)) DO
  334.             BEGIN
  335.             aMenuHandle := aMenuRecPtr^.menuOH;
  336.  
  337.             IF qDebug & NOT IsHandle(aMenuHandle) THEN
  338.                 BEGIN
  339.                 IF VerboseIsHandle(aMenuHandle) THEN;
  340.                 WrLblPtr('Bad menuHandle was', aMenuHandle);
  341.                 ProgramBreak('I guess it''s not a MenuHandle, huh?');
  342.                 END
  343.             ELSE
  344.                 FailNIL(aMenuHandle);
  345.  
  346.             IF (qDebug | qInspector) & (aMenuHandle^^.menuID = mDebug) THEN {??? why? }
  347.                 BEGIN
  348.                 aMenuHandle^^.menuID := 0;                { store info about debug menu in index 0 }
  349.                 DoToMenu(aMenuHandle, isHierarchical);
  350.                 aMenuHandle^^.menuID := mDebug;
  351.                 END
  352.             ELSE
  353.             DoToMenu(aMenuHandle, isHierarchical);
  354.  
  355.             aMenuRecPtr := MAMenuRecPtr(ORD(aMenuRecPtr) + SizeOf(MAMenuRec));
  356.             END;
  357.         END;
  358.  
  359.     BEGIN
  360.     { Do regular menus }
  361.     
  362.     wasLocked :=  IsHandleLocked(GetMenuList);
  363.     LockHandleHigh(GetMenuList);
  364.     
  365.     WITH MADynamicMenuListHandle(GetMenuList)^^ DO
  366.         WalkAMenuRecArray(MAMenuRecPtr(@menu), lastMenu, kNotHierArchical);
  367.  
  368.     { Now do hierarchial menus }
  369.     IF (qNeedsHierarchicalMenus | gConfiguration.hasHierarchicalMenus) & includeHierarchical THEN
  370.         WITH MADynamicMenuListHandle(GetMenuList)^^ DO
  371.             WalkAMenuRecArray(MAMenuRecPtr(ORD(@menu) + lastMenu + SizeOf(INTEGER) +
  372.                                            SizeOf(PixMapHandle)), IntegerPtr(ORD(@menu) +
  373.                               lastMenu)^, kHierArchical);
  374.     IF NOT wasLocked THEN
  375.         HUnlock(GetMenuList);
  376.     END;
  377.  
  378. {--------------------------------------------------------------------------------------------------}
  379. {$S MAMenuRes}
  380.  
  381. PROCEDURE Enable(aCmd: CmdNumber;
  382.                  canDo: Boolean);
  383.  
  384.     VAR
  385.         menu, item:         INTEGER;
  386.         aMenuHandle:        MenuHandle;
  387.  
  388.     BEGIN
  389.     {$IFC qDebug}
  390.     IF gTraceSetupMenus THEN
  391.         Writeln('..... Enable(', TraceMenuName(aCmd), gBoolString[canDo], ')');
  392.     {$ENDC}
  393.     aMenuHandle := CmdToComponents(aCmd, menu, item);
  394.     IF aMenuHandle <> NIL THEN
  395.         IF canDo THEN
  396.             EnableItem(aMenuHandle, item)
  397.         ELSE
  398.             DisableItem(aMenuHandle, item);
  399.     END;
  400.  
  401. {--------------------------------------------------------------------------------------------------}
  402. {$S MAMenuRes}
  403.  
  404. PROCEDURE EnableCheck(aCmd: CmdNumber;
  405.                       canDo, checkIt: Boolean);
  406.  
  407.     VAR
  408.         menu, item:         INTEGER;
  409.         aMenuHandle:        MenuHandle;
  410.  
  411.     BEGIN
  412.     {$IFC qDebug}
  413.     IF gTraceSetupMenus THEN
  414.         Writeln('..... EnableCheck(', TraceMenuName(aCmd), gBoolString[canDo], ', ',
  415.                 gBoolString[checkIt], ')');
  416.     {$ENDC}
  417.     aMenuHandle := CmdToComponents(aCmd, menu, item);
  418.     IF aMenuHandle <> NIL THEN
  419.         BEGIN
  420.         IF canDo THEN
  421.             EnableItem(aMenuHandle, item)
  422.         ELSE
  423.             DisableItem(aMenuHandle, item);
  424.         CheckItem(aMenuHandle, item, checkIt);
  425.         END;
  426.     END;
  427.  
  428. {--------------------------------------------------------------------------------------------------}
  429. {$S MAMenuRes}
  430.  
  431. FUNCTION GetResMenu(menuResID: INTEGER): MenuHandle;
  432. { Allow us to get a menu when it's not available via GetMHandle. 
  433. !!! Really should perform the other functions of GetMenu (load menuproc, color table, etc.}
  434.  
  435.     PROCEDURE DoGetResMenu;
  436.  
  437.         BEGIN
  438.         GetResMenu := MenuHandle(GetResource('MENU', menuResID));
  439.         END;
  440.  
  441.     BEGIN
  442.     WithApplicationResFileDo(DoGetResMenu);
  443.     END;
  444.  
  445. {--------------------------------------------------------------------------------------------------}
  446. {$S MAInit}
  447.  
  448. PROCEDURE InitUMenuSetup;
  449.  
  450.     TYPE
  451.         JmpRecPtr            = ^JmpRec;
  452.         JmpRec                = RECORD
  453.             opcode:             INTEGER;
  454.             target:             Ptr;
  455.             END;
  456.  
  457.         {$IFC qDebug}
  458.  
  459.     VAR
  460.         i:                    INTEGER;
  461.         previousCmdNumber:    INTEGER;
  462.         {$ENDC}
  463.  
  464.     BEGIN
  465.     { read in the command table }
  466.     pCmdTable := CmdTableHandle(GetResource(kMNTBbyCmdNumber, kIDMNTBbyCmdNumber));
  467.     FailNilResource(pCmdTable);
  468.     pSizeCmdTable := GetHandleSize(Handle(pCmdTable)) DIV SIZEOF(MenuCmdRecord);
  469.  
  470.     {$IFC qDebug}
  471.     previousCmdNumber := MAXINT;
  472.     FOR i := 1 TO pSizeCmdTable DO
  473.         BEGIN
  474.         IF pCmdTable^^[i].theCmdNumber = previousCmdNumber THEN
  475.             ProgramBreak(ConcatNumber('Duplicate command number not allowed: ', previousCmdNumber));
  476.         previousCmdNumber := pCmdTable^^[i].theCmdNumber;
  477.         END;
  478.     {$ENDC}
  479.  
  480.     pHNullMenuProc := NewPermHandle(6);
  481.     FailNIL(pHNullMenuProc);
  482.     WITH JmpRecPtr(pHNullMenuProc^)^ DO
  483.         BEGIN
  484.         opcode := $4EF9;                                { JMP }
  485.         target := @NullMenuProc;
  486.         END;
  487.     END;
  488.  
  489. {--------------------------------------------------------------------------------------------------}
  490. {$S MAMenuRes}
  491.  
  492. FUNCTION MAGetMenu(menuNo: INTEGER): MenuHandle;
  493.  
  494.     VAR
  495.         theMenu: MenuHandle;
  496.  
  497.     BEGIN
  498.     theMenu := GetMHandle(menuNo); { do this first ... the menu is likely to be in the menubar and
  499.                                     more likely of success, hence, faster }
  500.     IF theMenu = NIL THEN
  501.         theMenu := GetResMenu(menuNo);
  502.  
  503.     MAGetMenu := theMenu;
  504.     END;
  505.  
  506.  
  507. {--------------------------------------------------------------------------------------------------}
  508. {$S MAInit}
  509.  
  510. FUNCTION MAGetNewMBar(menuRsrcID: INTEGER): Handle;
  511.  
  512.     VAR
  513.         theColorTab:        MCTableHandle;
  514.         theColorRsrc:        MAMenuCRsrcHandle;
  515.         itsRsrcHandle:        Handle;
  516.         savedState:            SignedByte;
  517.  
  518.     BEGIN
  519.     IF qNeedsColorQD | gConfiguration.hasColorQD THEN
  520.         theColorTab := GetMCInfo;
  521.     
  522.     { make the 'MBAR' resource non-purgeable, so the Toolbox doesn't die }
  523.     itsRsrcHandle := GetResource('MBAR', menuRsrcID);
  524.     IF itsRsrcHandle <> NIL THEN
  525.         BEGIN
  526.         savedState := HGetState(itsRsrcHandle);
  527.         HNoPurge(itsRsrcHandle);
  528.         END;
  529.  
  530.     MAGetNewMBar := GetNewMBar(menuRsrcID);
  531.  
  532.     { restore the 'MBAR' resource }
  533.     IF itsRsrcHandle <> NIL THEN
  534.         HSetState(itsRsrcHandle, savedState);
  535.     
  536.     IF (theColorTab <> NIL) THEN
  537.         IF qNeedsColorQD | gConfiguration.hasColorQD THEN
  538.             BEGIN
  539.             HLock(Handle(theColorTab));
  540.             SetMCEntries(GetHandleSize(Handle(theColorTab)) DIV SIZEOF(MCEntry), theColorTab^);
  541.             HUnlock(Handle(theColorTab));
  542.             DispMCInfo(theColorTab);
  543.             END;
  544.     END;
  545.  
  546. {--------------------------------------------------------------------------------------------------}
  547. {$S MAMenuRes}
  548.  
  549. PROCEDURE MAInsertMenu(theMenu: MenuHandle;
  550.                        beforeID: INTEGER);
  551.  
  552.     VAR
  553.         theColorRsrc:        MAMenuCRsrcHandle;
  554.  
  555.     BEGIN
  556.     InsertMenu(theMenu, beforeID);
  557.  { Since only GetMenu automatically loads the appropriate color information,
  558.   and (sigh) since we can only call GetMenu once, and if you call DeleteMenu
  559.   all the good color stuff goes away (double sigh) we'll have to help out
  560.   the Menu Manager by doing its job for it }
  561.     IF qNeedsColorQD | gConfiguration.hasColorQD THEN
  562.         BEGIN
  563.         theColorRsrc := MAMenuCRsrcHandle(GetResource('mctb', theMenu^^.menuID));
  564.         IF theColorRsrc <> NIL THEN
  565.             BEGIN
  566.             HLock(Handle(theColorRsrc));
  567.             WITH theColorRsrc^^ DO
  568.                 SetMCEntries(numEntries, @data[1]);
  569.             HUnlock(Handle(theColorRsrc));
  570.             ReleaseResource(Handle(theColorRsrc));
  571.             END;
  572.         END;
  573.     END;
  574.  
  575. {--------------------------------------------------------------------------------------------------}
  576. {$S MAMenuRes}
  577.  
  578. PROCEDURE NeedCalcMenuSize(aMenuHandle: MenuHandle);
  579.  
  580.     BEGIN
  581.     WITH aMenuHandle^^ DO
  582.         IF menuProc = pHNullMenuProc THEN
  583.             menuWidth := 0;
  584.     END;
  585.  
  586. {--------------------------------------------------------------------------------------------------}
  587. {$S MAMenuRes}
  588.  { a null menuProc that is used to inhibit re-calculating the menu's size after each
  589.   call to EnableItem, CheckItem, etc. }
  590.  
  591. PROCEDURE NullMenuProc(message: INTEGER;
  592.                        aMenuHandle: MenuHandle;
  593.                        VAR menuRect: Rect;
  594.                        hitPt: Point;
  595.                        VAR whichItem: INTEGER);
  596.  
  597.     BEGIN
  598.     aMenuHandle^^.menuWidth := 0;
  599.     END;
  600.  
  601. {--------------------------------------------------------------------------------------------------}
  602. {$S MAMenuRes}
  603.  
  604. PROCEDURE PerformMenuSetup(PROCEDURE TheMenuSetterUpper);
  605.  
  606.     CONST
  607.         kDoHierArchical        = TRUE;
  608.         kDontDoHierArchical    = NOT kDoHierArchical;
  609.  
  610.         { If hierarchical the range of IDs for applications is restricted
  611.         See IM V-236. }
  612.         kHierarchicalMin    = 0;
  613.         kHierarchicalMax    = 235;
  614.  
  615.  
  616.     TYPE
  617.         EnableArray         = PACKED ARRAY [0..mLastMenu] OF Boolean; { Saved enable flags }
  618.         SavePrArray         = ARRAY [0..mLastMenu] OF Handle; { Saved menu procs }
  619.  
  620.     VAR
  621.         aMenuHandle:        MenuHandle;
  622.         wasEnabled:         EnableArray;
  623.         savedProcs:         SavePrArray;
  624.  
  625. FUNCTION IsManagedMenu(aMenuHandle: MenuHandle; isHierarchical: Boolean): BOOLEAN;
  626.  
  627.     BEGIN
  628.     WITH aMenuHandle^^ DO
  629.     IsManagedMenu := (((menuID >= mFirstMenu) & (menuID <= mLastMenu)) { Range of managed menus }
  630.            & (menuID <> mApple)                                        { _NEVER_ managed! }
  631.            & (NOT isHierarchical                                    { No further restrictions, unless… }
  632.            | (isHierarchical & (menuID >= kHierarchicalMin) & (menuID <= kHierarchicalMax)))) { must
  633.                be in valid range }
  634.     END;
  635.  
  636. PROCEDURE StartMenuSetup(aMenuHandle: MenuHandle; isHierarchical: Boolean);
  637.  
  638.     VAR
  639.         item: INTEGER;
  640.         theCmd: CHAR;
  641.  
  642.     BEGIN
  643.     IF IsManagedMenu(aMenuHandle, isHierarchical) THEN
  644.         WITH aMenuHandle^^ DO
  645.             BEGIN
  646.                 { Remember the menu itself was enabled, and disable the menu
  647.                  and all of its items. }
  648.             wasEnabled[menuID] := Odd(enableFlags);
  649.             enableFlags := 0;
  650.  
  651.                 { Save the menu's menuproc and set it to the NullMenuProc, so that
  652.                  CalcMenuSize is disabled (will do ÇalcMenuSize at end of setup). }
  653.             savedProcs[menuID] := menuProc; { See comment below }
  654.             menuProc := pHNullMenuProc;
  655.  
  656.             { Uncheck all items. }
  657.             FOR item := 1 TO CountMItems(aMenuHandle) DO
  658.               { Make sure we don't check items with sub-menus }
  659.                 IF qNeedsHierarchicalMenus | gConfiguration.hasHierarchicalMenus THEN
  660.                     BEGIN
  661.                     GetItemCmd(aMenuHandle, item, theCmd);
  662.                     IF ORD(theCmd) <> hMenuCmd THEN
  663.                         CheckItem(aMenuHandle, item, FALSE);
  664.                     END
  665.                 ELSE
  666.                     CheckItem(aMenuHandle, item, FALSE);
  667.             END;
  668.     END;
  669.  
  670. PROCEDURE EndMenuSetup(aMenuHandle: MenuHandle; isHierarchical: Boolean);
  671.  
  672.     VAR
  673.         newFlags: LongInt;
  674.         menuID: INTEGER;
  675.  
  676.     BEGIN
  677.     IF IsManagedMenu(aMenuHandle, isHierarchical) THEN
  678.         WITH aMenuHandle^^ DO
  679.             BEGIN
  680.  
  681.             newFlags := enableFlags;
  682.             { If any items are enabled, enable the menu }
  683.             IF newFlags <> 0 THEN
  684.                 BEGIN
  685.                 newFlags := BOR(1, newFlags);
  686.                 enableFlags := newFlags;
  687.                 END;
  688.  
  689.             { If the menu's enabled state changed, we have to draw the menu bar. }
  690.             IF Odd(newFlags) <> wasEnabled[menuID] THEN
  691.                 InvalidateMenuBar;
  692.  
  693.             { Restore the menuproc. }
  694.             menuProc := savedProcs[menuID];
  695.  
  696.                 { menuWidth set to 0 by routines that require CalcMenuSize, by
  697.                  calling NeedCalcMenu. }
  698.             IF menuWidth = 0 THEN
  699.                 CalcMenuSize(aMenuHandle);
  700.             END;
  701.     END;
  702.  
  703.     BEGIN
  704.     EachMenuDo(StartMenuSetup, kDoHierArchical);
  705.     TheMenuSetterUpper;
  706.     EachMenuDo(EndMenuSetup, kDoHierArchical);
  707.  
  708.     IF MenuBarHasPendingUpdate THEN
  709.         BEGIN
  710.         DrawMenuBar;
  711.         ValidateMenuBar;
  712.         END;
  713.  
  714.     ValidateMenus;
  715.     END;
  716.  
  717. {--------------------------------------------------------------------------------------------------}
  718. {$S MAMenuRes}
  719.  
  720. PROCEDURE SetCmdIcon(aCmd: CmdNumber;
  721.                      menuIcon: Byte);
  722.  
  723.     VAR
  724.         menu, item:         INTEGER;
  725.         aMenuHandle:        MenuHandle;
  726.  
  727.     BEGIN
  728.     {$IFC qDebug}
  729.     IF gTraceSetupMenus THEN
  730.         Writeln('..... SetCmdIcon(', TraceMenuName(aCmd), menuIcon: 1, ')');
  731.     {$ENDC}
  732.     aMenuHandle := CmdToComponents(aCmd, menu, item);
  733.     IF aMenuHandle <> NIL THEN
  734.         SetItemIcon(aMenuHandle, item, menuIcon);
  735.     END;
  736.  
  737. {--------------------------------------------------------------------------------------------------}
  738. {$S MAMenuRes}
  739.  
  740. PROCEDURE SetCmdName(aCmd: CmdNumber;
  741.                      menuText: Str255);
  742.  
  743.     VAR
  744.         menu, item:         INTEGER;
  745.         aMenuHandle:        MenuHandle;
  746.  
  747.     BEGIN
  748.     {$IFC qDebug}
  749.     IF gTraceSetupMenus THEN
  750.         Writeln('..... SetCmdName(', TraceMenuName(aCmd), '“', menuText, '”)');
  751.     {$ENDC}
  752.     aMenuHandle := CmdToComponents(aCmd, menu, item);
  753.     IF aMenuHandle <> NIL THEN
  754.         SetItem(aMenuHandle, item, menuText);
  755.     END;
  756.  
  757. {--------------------------------------------------------------------------------------------------}
  758. {$S MAMenuRes}
  759.  
  760. PROCEDURE SetIndCmdName(aCmd: CmdNumber;
  761.                         rsrcID, strIndex: INTEGER);
  762.  
  763.     VAR
  764.         s:                    Str255;
  765.  
  766.     BEGIN
  767.     GetIndString(s, rsrcID, strIndex);
  768.     SetCmdName(aCmd, s);
  769.     END;
  770.  
  771. {--------------------------------------------------------------------------------------------------}
  772. {$S MAMenuRes}
  773.  
  774. PROCEDURE SetMenuState(aCmd: CmdNumber;
  775.                        rsrcID, falseBuzzItem, trueBuzzItem: INTEGER;
  776.                        stateVariable: Boolean);
  777.  
  778.     VAR
  779.         buzzItem:            INTEGER;
  780.  
  781.     BEGIN
  782.     IF stateVariable THEN
  783.         buzzItem := trueBuzzItem
  784.     ELSE
  785.         buzzItem := falseBuzzItem;
  786.  
  787.     SetIndCmdName(aCmd, rsrcID, buzzItem);
  788.     END;
  789.  
  790. {--------------------------------------------------------------------------------------------------}
  791. {$S MAMenuRes}
  792.  
  793. PROCEDURE SetStyle(aCmd: CmdNumber;
  794.                    aStyle: Style);
  795.  
  796.     VAR
  797.         menu, item:         INTEGER;
  798.         aMenuHandle:        MenuHandle;
  799.  
  800.     BEGIN
  801.     {$IFC qDebug}
  802.     IF gTraceSetupMenus THEN
  803.         Writeln('..... SetStyle(', TraceMenuName(aCmd), Ptr(@aStyle)^: 1, ')');
  804.     {$ENDC}
  805.     aMenuHandle := CmdToComponents(aCmd, menu, item);
  806.     IF aMenuHandle <> NIL THEN
  807.         SetItemStyle(aMenuHandle, item, aStyle);
  808.     END;
  809.